home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
TeX 1995 July
/
TeX CD-ROM July 1995 (Disc 1)(Walnut Creek)(1995).ISO
/
dviware
/
ivd2dvi
/
auxiliary.c
< prev
next >
Wrap
C/C++ Source or Header
|
1990-10-01
|
16KB
|
592 lines
/*
* Auxiliary routines for ivd2dvi. Copyright 1988 by Larry Denenberg.
* May be freely distributed as long as this notice is retained.
*/
#include <stdio.h>
#include "commands.h"
#include "global.h"
/* Procedures and global variables defined in io.c */
extern unsigned BufSize;
extern unsigned_byte CopyByte(), ReadByte(), FReadByte();
extern long FReadUnsigned(), FReadSigned(), ReadUnsigned(), ReadSigned();
extern long CopyWord();
extern void WriteByte(), CopyNBytes(), SkipNBytes(), FSkipNBytes();
extern void InitIOBuffers(), BufOverflow(), WriteNumber();
/* Global variables defined in ivd2dvi.c */
extern char *ProgramName;
extern long XInput, XOutput, WInput, WOutput, DeltaH;
extern int State;
extern boolean ExactOutput;
/* Global variables defined here */
int FilePushLevel; /* current excess of PUSH over POP */
int MaxFilePushLevel; /* maximum FilePushLevel seen so far */
char *TeXFontDirs; /* directories to search for TFM files */
int NTeXFontDirs; /* number of directories in TeXFontDirs */
FILE *tfmfp; /* fp for currently open TFM file */
font *CurFont; /* font from which we're typesetting */
font *FirstFont; /* head of linked list of all fonts */
long *AuxStackPointer; /* first unused spot on the aux stack */
long *AuxBeginStack; /* first usable spot on the aux stack */
long *AuxEndStack; /* first location beyond the aux stack */
/* Procedures defined in this file, in order of definition */
void Initializations();
void PushWX(), PopXW(), PushDeltaH(), PopDeltaH(), AuxPush();
long AuxPop();
void PushWrite(), PopWrite(), MaxPushLevelOutput();
font *FindFont();
void FontDefine(), NewFont();
long WordMaybeRead();
unsigned_byte ByteMaybeRead();
void CopyFontDefinition(), SkipFontDefinition();
long CharWidth();
void ReadTFMFile();
boolean TFMOpen(), TFMTrialOpen();
void TFMHeaderLoad(), TFMWidthsLoad(), FontMemoryOverflow();
void BadDVIAbort();
/*
* Global initializations. At this point, the command line has been
* processed, so we know /BufSize/ and /ProgramName/. After trivial
* initializations, we change /TeXFontDirs/ from a colon-separated list
* to a sequence of null-terminated strings by simply changing each
* colon to a null and keeping a count in /NTeXFontDirs/. Finally, we
* set up the /AuxStack/ along with its pointer and end; giving it
* four times the size of a small stack since /PushWX/ puts four things
* on it at a time.
*/
void
Initializations()
{
char *pchar;
State = LTYPESETTING;
CurFont = FirstFont = NULL;
MaxFilePushLevel = FilePushLevel = 0;
InitIOBuffers();
TeXFontDirs = getenv("TEXFONTS");
if (TeXFontDirs == NULL) TeXFontDirs = TFMAREADEFAULT;
if (*TeXFontDirs == ':') TeXFontDirs++;
for (NTeXFontDirs = 0, pchar = TeXFontDirs; *pchar; NTeXFontDirs++) {
while (*pchar && (*pchar != ':')) pchar++;
if (*pchar == ':') *pchar++ = '\0';
}
AuxBeginStack = SEQALLOC(4*(BufSize/SMALLBUFDIVISOR), long);
AuxEndStack = AuxBeginStack + 4*(BufSize/SMALLBUFDIVISOR);
AuxStackPointer = AuxBeginStack;
if (AuxBeginStack == NULL) {
fprintf(stderr, "\n%s fatal error: can't allocate buffers\n",
ProgramName);
exit(3);
}
}
/*
* Save the horizontal motion parameters on the aux stack.
*/
void
PushWX()
{
AuxPush(WInput);
AuxPush(WOutput);
AuxPush(XInput);
AuxPush(XOutput);
}
/*
* Restore the horizontal motion parameters from the aux stack.
*/
void
PopXW()
{
XOutput = AuxPop();
XInput = AuxPop();
WOutput = AuxPop();
WInput = AuxPop();
}
/*
* Save /DeltaH/. We use the same stack as /PushWX/; only /EndReflect/
* has to worry about the necessary stack discipline.
*/
void
PushDeltaH()
{
AuxPush(DeltaH);
}
/*
* Restore /DeltaH/.
*/
void
PopDeltaH()
{
DeltaH = AuxPop();
}
/*
* Push /value/ onto the auxiliary stack.
*/
void
AuxPush(value)
long value;
{
*AuxStackPointer++ = value;
if (AuxStackPointer >= AuxEndStack) BufOverflow();
}
/*
* Pop a value from the auxiliary stack. Underflow means that
* something is seriously wrong; even bad input shouldn't do it.
*/
long
AuxPop()
{
if (--AuxStackPointer < AuxBeginStack) {
fprintf(stderr, "\n%s internal error: simulation stack underflow\n",
ProgramName);
exit(4);
}
return *AuxStackPointer;
}
/*
* Write a PUSH command to the output DVI file. All such commands must
* be written by this routine so we can keep an accurate count of how
* deep we are. /FilePushLevel/ keeps this count and /MaxFilePushLevel/
* keeps track of the deepest we've ever been. (This routine should be
* called WritePush, but then its name would conflict with WritePop.)
*/
void
PushWrite()
{
WriteByte(PUSH);
if (++FilePushLevel > MaxFilePushLevel)
MaxFilePushLevel = FilePushLevel;
}
/*
* Write a POP command to the output DVI file. All such commands must
* be written by this routine, so we can keep an accurate count of how
* deep we are. The error here shouldn't occur no matter what garbage
* is in the DVI file since this stuff is checked at an even lower
* level; see /NestingValidate/ in io.c.
*/
void
PopWrite() {
WriteByte(POP);
if (--FilePushLevel < 0) {
fprintf(stderr, "\n%s internal error: more pops than pushes!\n",
ProgramName);
exit(4);
}
}
/*
* Write out the maximum stack depth necessary to process this file.
* That number is exactly /MaxFilePushLevel/, as computed by the two
* routines immediately preceding. However, we start by reading the
* old value, and use it instead if it's big enough and the -X flag
* was used. Here's the reason: TeX doesn't always put the correct
* value in this field! If TeX is writing out a POP that immediately
* follows a PUSH, they are both dropped and nothing goes to the DVI
* file. But the variable that's worrying about the maximum stack
* depth is not informed of this optimization. So if TeX tries to
* write "PUSH PUSH PUSH POP POP POP" it thinks that the max stack
* depth is 3, but in fact nothing is written. Thus TeX's behavior
* is always conservative. See paragraphs 601, 619, and 629 of
* Volume B of {\it Computers and Typesetting}.
*/
void
MaxPushLevelOutput()
{
long inputlevel;
inputlevel = ReadUnsigned(2);
if (ExactOutput && (inputlevel > MaxFilePushLevel))
WriteNumber(inputlevel, 2);
else
WriteNumber((long) MaxFilePushLevel, 2);
}
/*
* Find the font associated with /fontnumber/ by searching the list.
* If it's not there, return NULL and let the caller worry.
*/
font *
FindFont(fontnumber)
long fontnumber;
{
font *f;
f = FirstFont;
while ((f != NULL) && (f->number != fontnumber)) f = f->nextfont;
return f;
}
/*
* Define a new font as required by a FNT_DEFn command. If the font is
* already known, we must have seen this FNT_DEFn before---skip it if
* simulating, otherwise copy it over. (A given FNT_DEFn command may be
* seen any number of times because we must process them whether we're
* simulating or typesetting.) Call /NewFont/ on never-yet-seen fonts.
*/
void
FontDefine(bytes)
unsigned bytes;
{
long fontnumber;
fontnumber = ReadUnsigned(bytes);
if (FindFont(fontnumber) == NULL)
NewFont(fontnumber, bytes);
else if (State >= SIMULATING)
SkipFontDefinition();
else
CopyFontDefinition(fontnumber, bytes);
}
/*
* Process a font for the first time. If we're not simulating, we must
* copy the FNT_DEFn command and parameters into the output file as we
* read them. Allocate the new font object and link it into the list.
* Fill in the /number/, /checksum/, /scalefactor/, /area/, and /name/
* fields from the arguments (skip the design size; we don't need it).
* Set /loaded/ to FALSE to indicate that we haven't read the TFM file.
* Only when we need the width of a character in the font---when
* /CharWidth/ is called---do we load the TFM file and fill in the rest
* of the fields. That is, we never read the TFM files of fonts that
* aren't used in reflected text.
*/
void
NewFont(fontnumber, bytes)
long fontnumber;
unsigned bytes;
{
font *newfont;
unsigned areasize, namesize;
char *p;
if (State < SIMULATING) {
WriteByte(FNT_DEF1 + bytes - 1);
WriteNumber(fontnumber, bytes);
}
newfont = OBJALLOC(font);
if (newfont == NULL) FontMemoryOverflow();
newfont->nextfont = FirstFont;
FirstFont = newfont;
newfont->number = fontnumber;
newfont->checksum = WordMaybeRead();
newfont->scalefactor = WordMaybeRead();
WordMaybeRead();
areasize = ByteMaybeRead();
namesize = ByteMaybeRead();
newfont->area = (char *) calloc(areasize+1, sizeof(char));
if (newfont->area == NULL) FontMemoryOverflow();
for (p = newfont->area; areasize != 0; areasize--) *p++ = ByteMaybeRead();
*p = '\0';
newfont->name = (char *) calloc(namesize+1, sizeof(char));
if (newfont->name == NULL) FontMemoryOverflow();
for (p = newfont->name; namesize != 0; namesize--) *p++ = ByteMaybeRead();
*p = '\0';
newfont->loaded = FALSE;
}
/*
* Either read or copy a word, depending on whether we're simulating.
* This routine and the next are useful because the definition of a
* font might be seen for the first time during a simulation or
* during normal left-to-right typesetting. Thus /NewFont/ might or
* might not want to copy out parameters as they're read.
*/
long
WordMaybeRead()
{
if (State >= SIMULATING) return ReadSigned(4); else return CopyWord();
}
/*
* Either read or copy a byte, depending on whether we're simulating.
*/
unsigned_byte
ByteMaybeRead()
{
if (State >= SIMULATING) return ReadUnsigned(1); else return CopyByte();
}
/*
* Copy a font definition from the input DVI file to the output file.
*/
void
CopyFontDefinition(fontnumber, bytes)
long fontnumber;
unsigned bytes;
{
WriteByte(FNT_DEF1 + bytes - 1);
WriteNumber(fontnumber, bytes);
CopyNBytes(12L);
CopyNBytes((long) (CopyByte() + CopyByte()));
}
/*
* Skip by a font definition. The FNT_DEFn command and the first
* parameter have already been skipped.
*/
void
SkipFontDefinition()
{
SkipNBytes(12L);
SkipNBytes((long) (ReadUnsigned(1) + ReadUnsigned(1)));
}
/*
* Find the width of character /c/ in /CurFont/. If the TFM file hasn't
* been read, read it. The /widths/ field is NULL in fonts whose TFM
* files we couldn't find; we just return 0 as the width of any character
* in such a font. Carefully reduce /c/ modulo 256 if necessary. If /c/
* is now between /bc/ and /ec/, it's a character in the font. Get its
* value from the /charwidths/ table (whose indices run from 0 to
* /ec/-/bc/) and use that number to index the /widths/ table. If /c/
* isn't in the font, issue a warning and return 0.
*/
long
CharWidth(c)
long c;
{
if (CurFont->loaded == FALSE) ReadTFMFile(CurFont);
if (CurFont->widths == NULL) return 0L;
if (c < 0) c = 255 - ((-1 - c) % 256);
else if (c >= 256) c = c % 256;
if ((c >= CurFont->bc) && (c <= CurFont->ec) &&
(CurFont->charwidths[c - CurFont->bc] != 0))
return CurFont->widths[CurFont->charwidths[c - CurFont->bc]];
fprintf(stderr, "\n%s warning: character %d undefined in font %s\n",
ProgramName, c, CurFont->name);
return 0L;
}
/*
* Read in the width information for a font. This data isn't read until
* we actually need it, viz., the first time /CharWidth/ is called with
* /f/ in /CurFont/. If we can't find the TFM file, we set /f->widths/
* to NULL as a flag meaning "assume all widths are zero." In any case,
* we mark /f/ as "loaded" so we don't do this again.
*/
void
ReadTFMFile(f)
font *f;
{
if (TFMOpen(f)) {
TFMHeaderLoad(f);
TFMWidthsLoad(f);
(void) fclose(tfmfp);
} else
f->widths = NULL;
f->loaded = TRUE;
}
/*
* Open the TFM file for a font, returning TRUE if we did so and FALSE
* otherwise. If the name of the font starts with a slash, we only
* try to open the exact file. Otherwise we try prepending each of
* the possible TFM directories until we get a hit or run out. Recall
* that at this point /TeXFontDirs/ is a null-separated list of names.
*/
boolean
TFMOpen(f)
font *f;
{
char *pchar;
int ndir;
if ((*f->area == '/') || ((!*f->area) && (*f->name == '/'))) {
if (TFMTrialOpen("", f->area, f->name)) return TRUE;
} else {
for (pchar = TeXFontDirs, ndir = NTeXFontDirs; ndir > 0; ndir--) {
if (TFMTrialOpen(pchar, f->area, f->name)) return TRUE;
while (*pchar++);
}
}
fprintf(stderr, "\n%s warning: Can't find TFM file for font %s; ",
ProgramName, f->name);
fprintf(stderr, "assuming zero width\n");
return FALSE;
}
/*
* Try to open a font file. The "area" is mostly empty for TeX, but
* you never can tell. On success, leave the file descriptor in the
* global variable /tfmfp/ and return TRUE, otherwise return FALSE.
*/
boolean
TFMTrialOpen(path,area,name)
char *path, *area, *name;
{
static char buffer[MAXFILENAMESIZE];
(void) sprintf(buffer, "%s/%s/%s.tfm", path, area, name);
tfmfp = fopen(buffer, "r");
if (tfmfp == NULL) return FALSE; else return TRUE;
}
/*
* Set up the remaining fields of the font structure. Get and store
* the first and last character codes and the number of distinct widths
* in the font. Allocate the tables /charwidths/ and /widths/. Check
* the checksum, but skip by the rest of the header. Finally, read the
* values into the /charwidths/ table.
*/
void
TFMHeaderLoad(f)
font *f;
{
int nchars;
long lh;
unsigned_byte *pbyte;
FSkipNBytes(tfmfp,2L);
lh = FReadUnsigned(tfmfp,2);
f->bc = FReadUnsigned(tfmfp,2);
f->ec = FReadUnsigned(tfmfp,2);
nchars = f->ec - f->bc + 1;
if (nchars < 0) nchars = 0;
if (nchars > 0) {
f->charwidths = SEQALLOC(nchars, unsigned_byte);
if (f->charwidths == NULL) FontMemoryOverflow();
}
f->nw = FReadUnsigned(tfmfp,2);
if (f->nw > 0) {
f->widths = SEQALLOC(nchars, long);
if (f->widths == NULL) FontMemoryOverflow();
}
FSkipNBytes(tfmfp,14L);
if (f->checksum != FReadSigned(tfmfp,4))
fprintf(stderr, "\n%s warning: checksum mismatch on font %s\n",
ProgramName, f->name);
FSkipNBytes(tfmfp, 4*lh - 4);
for (pbyte = f->charwidths; nchars > 0; nchars--) {
*pbyte++ = FReadByte(tfmfp);
FSkipNBytes(tfmfp,3L);
}
}
/*
* Read the character widths of a font from the TFM file and convert
* to DVI units, a calculation that must be done with extreme care.
* Further explanation is punted to section 571 of volume B of the
* Encyclop\ae dia TeXnica. The results go into the /widths/ table.
*/
void
TFMWidthsLoad(f)
font *f;
{
int nwidths;
unsigned_byte a,b,c,d;
long *pwidth,z,alpha,beta;
z = f->scalefactor;
alpha = 16;
while (z >= 040000000L) { z = z/2; alpha = alpha+alpha; }
beta = 256/alpha;
alpha *= z;
nwidths = f->nw;
for (pwidth = f->widths; nwidths > 0; nwidths--) {
a = FReadByte(tfmfp); b = FReadByte(tfmfp);
c = FReadByte(tfmfp); d = FReadByte(tfmfp);
*pwidth = (((((d * z) / 0400) + (c * z)) / 0400) + (b * z)) / beta;
if (a != 0) {
if (a != 255) {
fprintf(stderr, "\n%s fatal error: Bad TFM file for font %s\n",
ProgramName, f->name);
exit(2);
} else *pwidth -= alpha;
}
pwidth++;
}
}
/*
* Do you need comments for this one?
*/
void
FontMemoryOverflow()
{
fprintf(stderr, "\n%s: Insufficient memory for font definitions\n",
ProgramName);
exit(3);
}
/*
* Abort the run due to junk in the input.
*/
void
BadDVIAbort(message)
char *message;
{
fprintf(stderr, "\n%s: Malformed DVI file (%s)\n", ProgramName, message);
exit(2);
}